/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.editor;
import java.util.ArrayList;
import javax.swing.text.AbstractDocument;
import javax.swing.text.BadLocationException;
import javax.swing.event.DocumentEvent;
import javax.swing.undo.UndoableEdit;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.CannotRedoException;
/**
* Document implementation
*
* @author Miloslav Metelka
* @version 1.00
*/
public class BaseDocumentEvent extends AbstractDocument.DefaultDocumentEvent {
private DocOp.ModifyUndoEdit modifyUndoEdit;
/** Previous event in the chain of the events that were
* connected together to be undone/redone at once.
*/
private BaseDocumentEvent previous;
private boolean inUndo;
private boolean inRedo;
static final long serialVersionUID =-7624299835780414963L;
/** Construct document event instance.
* @param offset position in the document where the insert/remove/change
* occured
* @param length number of the characters affected by the event
* @param type type of the event - INSERT/REMOVE/CHANGE
*/
public BaseDocumentEvent(BaseDocument doc, int offset, int length,
DocumentEvent.EventType type) {
((AbstractDocument)doc).super(offset, length, type);
}
protected UndoableEdit findEdit(Class editClass) {
int cnt = edits.size();
for (int i = 0; i < cnt; i++) {
Object edit = edits.get(i);
if (editClass.isInstance(edit)) {
return (UndoableEdit)edit;
}
}
return null;
}
private DocOp.ModifyUndoEdit getModifyUndoEdit() {
if (getType() == DocumentEvent.EventType.CHANGE) {
throw new IllegalStateException("Cannot be called for CHANGE events."); // NOI18N
}
if (modifyUndoEdit == null) {
modifyUndoEdit = (DocOp.ModifyUndoEdit)findEdit(DocOp.ModifyUndoEdit.class);
}
return modifyUndoEdit;
}
/** Gets the characters that were inserted/removed or null
* for change event.
* Characters must be used only in readonly mode as the
* character array is shared by all listeners and also by
* modification event itself.
*/
public char[] getChars() {
return (getModifyUndoEdit() != null) ? getModifyUndoEdit().getChars() : null;
}
/** Get the text that was inserted/removed or null
* for change event.
*/
public String getText() {
return (getModifyUndoEdit() != null) ? getModifyUndoEdit().getText() : null;
}
/** Get the line at which the insert/remove occured */
public int getLine() {
return (getModifyUndoEdit() != null) ? getModifyUndoEdit().getLine() : 0;
}
/** Get the count of '\n' (line-feeds) contained in the inserted/removed text. */
public int getLFCount() {
return (getModifyUndoEdit() != null) ? getModifyUndoEdit().getLFCount() : 0;
}
/** Get the offset at which the updating of the syntax stopped so there
* are no more changes in the tokens after this point.
*/
public int getSyntaxUpdateOffset() {
return (getModifyUndoEdit() != null) ? getModifyUndoEdit().getSyntaxUpdateOffset() : 0;
}
public String getDrawLayerName() {
if (getType() != DocumentEvent.EventType.CHANGE) {
throw new IllegalStateException("Can be called for CHANGE events only."); // NOI18N
}
DrawLayerChange dlc = (DrawLayerChange)findEdit(DrawLayerChange.class);
return (dlc != null) ? dlc.getDrawLayerName() : null;
}
/** Whether this event is being fired because it's being undone. */
public boolean isInUndo() {
return inUndo;
}
/** Whether this event is being fired because it's being redone. */
public boolean isInRedo() {
return inRedo;
}
public void undo() throws CannotUndoException {
inUndo = true;
super.undo();
if (previous != null) {
previous.undo();
}
inUndo = false;
}
public void redo() throws CannotRedoException {
inRedo = true;
if (previous != null) {
previous.redo();
}
super.redo();
inRedo = false;
}
public String getUndoPresentationName() {
return "";
}
public String getRedoPresentationName() {
return "";
}
protected final BaseDocumentEvent getPrevious() {
return previous;
}
/** Returns true if this event can be merged by the previous
* one (given as parameter) in the undo-manager queue.
*/
public boolean canMerge(BaseDocumentEvent evt) {
if (getType() == DocumentEvent.EventType.INSERT) { // last was insert
if (evt.getType() == DocumentEvent.EventType.INSERT) { // adding insert to insert
String text = getText();
String evtText = evt.getText();
if ((getLength() == 1 || (getLength() > 1 && Analyzer.isSpace(text)))
&& (evt.getLength() == 1 || (evt.getLength() > 1
&& Analyzer.isSpace(evtText)))
&& (evt.getOffset() + evt.getLength() == getOffset()) // this follows the previous
) {
BaseDocument doc = (BaseDocument)getDocument();
boolean thisWord = doc.isIdentifierPart(text.charAt(0));
boolean lastWord = doc.isIdentifierPart(evtText.charAt(0));
if (thisWord && lastWord) { // add word char to word char(s)
return true;
}
boolean thisWhite = doc.isWhitespace(text.charAt(0));
boolean lastWhite = doc.isWhitespace(evtText.charAt(0));
if ((lastWhite && thisWhite)
|| (!lastWhite && !lastWord && !thisWhite && !thisWord)
) {
return true;
}
}
} else { // adding remove to insert
}
} else { // last was remove
if (evt.getType() == DocumentEvent.EventType.INSERT) { // adding insert to remove
} else { // adding remove to remove
}
}
return false;
}
/** Try to determine whether this event can replace the old one.
* This is used to batch the one-letter modifications into larger
* parts (words) and undoing/redoing them at once.
* This method returns true whether
*/
public boolean replaceEdit(UndoableEdit anEdit) {
BaseDocument doc = (BaseDocument)getDocument();
if (anEdit instanceof BaseDocumentEvent) {
BaseDocumentEvent evt = (BaseDocumentEvent)anEdit;
if (!doc.undoMergeReset && canMerge(evt)) {
// System.out.println("BaseDocumentEvent.java:185 this=" + this + ", merged with evt=" + evt);
previous = evt;
return true;
}
}
doc.undoMergeReset = false;
return false;
}
public void die() {
previous = null;
}
public String toString() {
return System.identityHashCode(this) + " " + super.toString()
+ ", type=" + getType()
+ ((getType() != DocumentEvent.EventType.CHANGE)
? ("text='" + getText() + "'") : "");
}
/** Edit describing the change of the document draw-layers */
static class DrawLayerChange extends AbstractUndoableEdit {
String drawLayerName;
DrawLayerChange(String drawLayerName) {
this.drawLayerName = drawLayerName;
}
public String getDrawLayerName() {
return drawLayerName;
}
}
}
/*
* Log
* 6 Gandalf-post-FCS1.5 4/5/00 Miloslav Metelka undo/redo naming removed
* 5 Gandalf-post-FCS1.4 4/4/00 Miloslav Metelka
* 4 Gandalf-post-FCS1.3 4/3/00 Miloslav Metelka undo update
* 3 Gandalf-post-FCS1.2 3/31/00 Miloslav Metelka fix
* 2 Gandalf-post-FCS1.1 3/27/00 Miloslav Metelka
* 1 Gandalf-post-FCS1.0 3/8/00 Miloslav Metelka
* $
*/